/*
 * @Project Name: JavaLabs
 * @File Name: DataTree.java
 * @Package Name: tool
 * @Date: 2017年6月26日上午9:57:51
 * @Creator: xuyuji-374
 * @line------------------------------
 * @修改人: 
 * @修改时间: 
 * @修改内容: 
 */

package tool;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据树工具类
 * 用途：替代树状结构数据的递归sql
 * 注意：非线程安全
 * @author xuyuji-374
 * @date 2017年6月26日上午9:57:51
 * @see
 */
public class DataTree<T> {

	private Map<String, TreeNode> nodeMap;
	
	private List<TreeNode> nodeList;
	
	/**
	 * isSort: 是否需要排序.默认不排序
	 */
	private boolean isSort;
	
	/**
	 * isAsc: 是否升序排序.默认升序
	 */
	private boolean isAsc;
	
	/**
	 * showRoot: 是否显示根节点.默认显示
	 */
	private boolean showRoot;
	
	private boolean isRebuild;
	
	public DataTree() {
		this.nodeMap = new HashMap<String, TreeNode>();
		this.nodeList = new ArrayList<TreeNode>();
		this.isSort = false;
		this.isAsc = true;
		this.showRoot = true;
		this.isRebuild = true;
	}
	
	public void addNode(int id, int parentId, T data){
		addNode(id, parentId, 0, data);
	}
	
	public void addNode(int id, int parentId, int sort, T data){
		addNode(String.valueOf(id), String.valueOf(parentId), sort, data);
	}
	
	public void addNode(long id, long parentId, T data){
		addNode(id, parentId, 0, data);
	}
	
	public void addNode(long id, long parentId, int sort, T data){
		addNode(String.valueOf(id), String.valueOf(parentId), sort, data);
	}
	
	public void addNode(String id, String parentId, T data){
		addNode(id, parentId, 0, data);
	}
	
	public void addNode(String id, String parentId, int sort, T data){
		this.isRebuild = true;
		TreeNode treeNode = new TreeNode(id, parentId, sort, data);
		nodeMap.put(id, treeNode);
		nodeList.add(treeNode);
	}
	
	public boolean isSort() {
		return isSort;
	}

	public DataTree<T> setSort(boolean isSort) {
		this.isSort = isSort;
		return this;
	}

	public boolean isAsc() {
		return isAsc;
	}
	
	public boolean isDesc() {
		return isAsc ? false : true;
	}

	public DataTree<T> setAsc() {
		this.isAsc = true;
		return this;
	}
	
	public DataTree<T> setDesc() {
		this.isAsc = false;
		return this;
	}

	public boolean isShowRoot() {
		return showRoot;
	}

	public DataTree<T> setShowRoot(boolean showRoot) {
		this.showRoot = showRoot;
		return this;
	}

	public List<T> getTreeList(int rootId){
		return getTreeList(String.valueOf(rootId));
	}
	
	public List<T> getTreeList(long rootId){
		return getTreeList(String.valueOf(rootId));
	}
	
	/**
	 * 获取递归结构列表
	 * @date 2017年6月30日下午6:46:09
	 * @author xuyuji-374
	 * @since 1.0.0 
	 * @param rootId
	 * @return
	 */
	public List<T> getTreeList(String rootId){
		buildNodeMap();
		
		TreeNode rootNode = nodeMap.get(rootId);
		if(rootNode == null){
			return new ArrayList<T>();
		}
		
		if(!showRoot){
			rootNode.setShow(false);
		}
		
		List<T> result = new ArrayList<T>();
		getTreeNode(rootNode, result);
		return result;
	}
	
	private void buildNodeMap(){
		if(isRebuild){
			for(TreeNode treeNode : nodeList){
				treeNode.emptyChilds();
			}
			for(TreeNode treeNode : nodeList){
				String parentId = treeNode.getParentId();
				TreeNode parentNode = nodeMap.get(parentId);
				if(parentNode != null){
					parentNode.addChild(treeNode);
				}else{
					parentNode = new TreeNode(parentId, null, 0, null, false);
					parentNode.addChild(treeNode);
					nodeMap.put(parentId, parentNode);
				}
			}
			isRebuild = false;
		}
	}
	
	private void getTreeNode(TreeNode treeNode, List<T> result){
		if(treeNode == null){
			return;
		}
		
		if(treeNode.isShow){
			result.add(treeNode.getData());
		}
		
		List<TreeNode> childs = treeNode.getChilds();
		if(isSort){
			Collections.sort(childs);
		}
		
		for(TreeNode child : childs){
			getTreeNode(child, result);
		}
	}
	
	public List<T> getParentList(int nodeId) {
		return getParentList(String.valueOf(nodeId));
	}
	
	public List<T> getParentList(long nodeId) {
		return getParentList(String.valueOf(nodeId));
	}
	
	/**
	 * 获取父节点递归结构
	 * @date 2017年7月4日上午10:59:54
	 * @author xuyuji-374
	 * @since 1.0.0 
	 * @param nodeId
	 * @return
	 */
	public List<T> getParentList(String nodeId){
		buildNodeMap();
		
		List<T> parentList = new ArrayList<>();
		String nowId = nodeId;
		while(true){
			TreeNode treeNode = nodeMap.get(nowId);
			if(treeNode == null){
				break;
			}
			if(treeNode.isShow()){
				parentList.add(treeNode.getData());
			}
			nowId = treeNode.getParentId();
		}
		
		return parentList;
	}
	
	class TreeNode implements Comparable<TreeNode> {
		private String id;
		private String parentId;
		private int sort;
		private T data;
		private boolean isShow;
		private List<TreeNode> childs;
		
		public TreeNode(String id, String parentId, int sort, T data) {
			this.id = id;
			this.parentId = parentId;
			this.sort = sort;
			this.data = data;
			this.isShow = true;
			this.childs = new ArrayList<>();
		}
		
		public TreeNode(String id, String parentId, int sort, T data, boolean isShow) {
			this.id = id;
			this.parentId = parentId;
			this.sort = sort;
			this.data = data;
			this.isShow = isShow;
			this.childs = new ArrayList<>();
		}
		
		public String getId() {
			return id;
		}
		
		public void setId(String id) {
			this.id = id;
		}
		
		public String getParentId() {
			return parentId;
		}
		
		public void setParentId(String parentId) {
			this.parentId = parentId;
		}
		
		public int getSort() {
			return sort;
		}
		
		public void setSort(int sort) {
			this.sort = sort;
		}
		
		public List<TreeNode> getChilds() {
			return childs;
		}
		
		public void addChild(TreeNode treeNode) {
			childs.add(treeNode);
		}
		
		public void emptyChilds(){
			this.childs = new ArrayList<>();
		}
		
		public T getData() {
			return data;
		}

		public void setData(T data) {
			this.data = data;
		}

		public boolean isShow() {
			return isShow;
		}

		public void setShow(boolean isShow) {
			this.isShow = isShow;
		}

		@Override
		public int compareTo(TreeNode o) {
			int otherSort = o.getSort();
			int result;
			
			if(sort > otherSort){
				result = 1;
			}else if(sort == o.getSort()){
				result = 0;
			}else{
				result = -1;
			}
			
			return isAsc ? result : result * -1;
		}
	}
	
	public static void main(String[] args) {
		DataTree<String> tree = new DataTree<String>();
		tree.addNode(3, 1, "node_3");
		tree.addNode(2, 1, "node_2");
		tree.addNode(1, 0, "node_1");
		
		for(String str : tree.getTreeList(0)){
			System.out.println(str);
		}
		
		System.out.println("#################");
		tree.addNode(0, -1, "node_0");
		tree.addNode(4, 2, "node_4");
		tree.addNode(5, 6, "node_5");
		
		for(String str : tree.getTreeList(0)){
			System.out.println(str);
		}
		
		System.out.println("#################");
		for(String str : tree.getParentList(4)){
			System.out.println(str);
		}
	}
}
